package de.reichelt.fxrequi;

import de.reichelt.fx.FXHelper;
import de.reichelt.fx.FxForm;
import de.reichelt.fxrequi.data.DataStore;
import de.reichelt.fxrequi.data.Project;
import de.reichelt.fxrequi.data.User;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import org.controlsfx.dialog.Dialogs;

public class FXrequi extends Application {
  
  /*
  Wenn im PRODUCTION-Modus, dann wird die Konfiguration, die Datenbank und die Logs 
  im User-Home-Verzeichnis, ansonsten im Projektverzeichnis erzeugt.
  */
  public static boolean PRODUCTION = false;
  
  public static FXrequi APP;
  /**
   * zeigt an, dann gerade interne Aktionen durchgeführt werden und deshalb keine 
   * Aktualisierung der Datenbereiche stattfinden darf
   */
  public static boolean BUSY;
  private Stage primaryStage;
  private Logger log;
  private String basePath;
  private FxForm formLogin;
  private BorderPane root;
  private Project selectedProject;
  
  public static void main(String[] args) {
    launch(args);
  }
  
  public FXrequi() {
    basePath = (PRODUCTION?System.getProperty("user.home"):".") + "/fxrequi";
    APP = this;
  }
  
  @Override
  public void start(Stage stage) throws Exception {
    File f = new File(basePath);
    if (!f.exists()) {
      f.mkdir();
    }
    String logCfg = basePath+"/logging.properties";
    initLogger(logCfg);
    System.setProperty("java.util.logging.config.file", basePath+"/logging.properties");
    log = Logger.getLogger(this.getClass().getName());
    log.info("FXrequi aufgerufen");
    Config.setPropertyFile(basePath+"/config.properties");
    Config.getInstance();
    DataStore.setDBPath(basePath);
    DataStore ds = DataStore.getInstance();
    
    this.primaryStage = stage;
    root = new BorderPane();
    setTopPane(null);
    FXMLLoader ldr = new FXMLLoader(this.getClass().getResource("ProjectView.fxml"));
    AnchorPane pane = (AnchorPane)ldr.load();
    setMainPane(pane);
    Scene scene = new Scene(root, 1000, 800);
    scene.getStylesheets().add("/de/reichelt/fxrequi/fxrequi.css");
    stage.setMinHeight(800);
    stage.setMinWidth(1000);
    stage.setTitle("Anforderungsverwaltung");
    stage.setScene(scene);
    stage.show();
    
    //TODO 0 Benutzeranmeldung implementieren wenn ProduktionModus
    if (!PRODUCTION) {
      ds.setLoginUser(new User("admin", "admin", "Administrator", true, null, null));
    } else {
      try {
        DialogWindow dlg = new DialogWindow("Anforderungsverwaltung", null);
        dlg.setHeight(200);
        dlg.setWidth(400);
        dlg.setResizable(false);
        generateLoginForm(dlg, "Benutzeranmeldung");
        dlg.showAndWait();
        if (dlg.getResult()==dlg.RESULT_OK) {
          log.fine("Login Result ok");
          //TODO 2 Login prüfen und angemeldeten Benutzer mit seinen Rechten merken
        }
      } catch (Exception ex) {
        log.log(Level.SEVERE, "Fehler beim Erzeugen des Projekt-Dialogs!", ex);
        showException("Fehler beim Erzeugen des Projekt-Dialogs!", ex);
      }
    }
  }
  
  private void initLogger(String filename) throws Exception {
    File logCfg = new File(filename);
    if (!logCfg.exists()) {
      logCfg.createNewFile();
      BufferedWriter out = new BufferedWriter(new FileWriter(logCfg));
      out.write("handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler\n");
      out.write("#handlers=java.util.logging.ConsoleHandler\n");
      out.write("#handlers=java.util.logging.FileHandler\n");
      out.write("java.util.logging.FileHandler.level=FINEST\n");
      out.write("java.util.logging.FileHandler.formatter=de.reichelt.fxrequi.MyLogFormatter\n");
      out.write("java.util.logging.FileHandler.pattern="+basePath+"/fxrequi-%u.log\n");
      out.write("java.util.logging.FileHandler.limit=500000\n");
      out.write("java.util.logging.FileHandler.count=5\n");
      out.write("java.util.logging.FileHandler.append=true\n");
      out.write("java.util.logging.ConsoleHandler.level=FINEST\n");
      out.write("java.util.logging.ConsoleHandler.formatter=de.reichelt.fxrequi.MyLogFormatter\n");
      out.write(".level=INFO\n");
      out.write("de.reichelt.level=FINEST\n");
      out.write("# level may be SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,OFF,ALL\n");
      out.close();
    }
  }
  
  private void generateLoginForm(DialogWindow dlg, String title) {
    AnchorPane pane = dlg.getPane();
    Label laTitle = new Label(title);
    laTitle.setAlignment(Pos.CENTER);
    laTitle.setStyle("-fx-font-size:18;");
    FXHelper.add2AnchorPane(pane, laTitle, 5.0, 5.0, 5.0, null);
    FXHelper.add2AnchorPane(pane, new Label("Benutzer:"), 5.0, 35.0, null, null);
    TextField txLoginName = new TextField();
    txLoginName.setPrefWidth(150);
    FXHelper.add2AnchorPane(pane, txLoginName, 100.0, 35.0, null, null);
    FXHelper.add2AnchorPane(pane, new Label("Passwort:"), 5.0, 65.0, null, null);
    PasswordField txLoginPassword = new PasswordField();
    txLoginPassword.setPrefWidth(150);
    FXHelper.add2AnchorPane(pane, txLoginPassword, 100.0, 65.0, null, null);
    Button btLogin = new Button("anmelden");
    btLogin.setDefaultButton(true);
    FXHelper.add2AnchorPane(pane, btLogin, 100.0, 95.0, null, null);
    Button btCancel = new Button("abbrechen");
    btCancel.setCancelButton(true);
    FXHelper.add2AnchorPane(pane, btCancel, 190.0, 95.0, null, null);
    formLogin = new FxForm();
    formLogin.registerButton(btLogin);
    formLogin.registerField(txLoginName, "username", true, true);
    formLogin.registerField(txLoginPassword, "password", true, true);
    btCancel.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        log.fine("aufgerufen");
        formLogin.resetErrors();
        if (dlg.result==dlg.RESULT_UNDEFINED) {
          dlg.setResult(dlg.RESULT_CANCELLED);
        }
        dlg.close();
      }
    });
    btLogin.setOnAction(new EventHandler<ActionEvent>() {
      @Override
      public void handle(ActionEvent event) {
        log.fine("aufgerufen");
        try {
          formLogin.resetErrors();
          if (formLogin.validate()) {
            log.info("Login ok");
//            DataStore ds = DataStore.getInstance();
//            User user = ds.getLoginUser();
//            dlg.setData(user);
            dlg.setResult(dlg.RESULT_OK);
            dlg.close();
          }
        } catch (Exception ex) {
          log.log(Level.SEVERE, "Fehler beim Prüfen der Projektversion!", ex);
          showException("Fehler beim Prüfen der Projektversion!", ex);
        }
      }
    });
  }
  
  public void setMainPane(Node node) {
    root.setCenter(node);
  }
  
  public void setTopPane(Pane pane) {
    root.setTop(pane);
  }
  
  public Stage getStage() {
    return primaryStage;
  }
  
  public void showError(String string) {
    Dialogs.create()
        .owner(primaryStage).title("Fehler").masthead(null).message(string).showError();
  }
  
  public void showException(String message, Exception ex) {
    Dialogs.create()
        .owner(primaryStage).title("Fehler").masthead(null).message(message).showException(ex);
  }

  public Project getSelectedProject() {
    log.fine("aufgerufen");
    return selectedProject;
  }

  public void setSelectedProject(Project selectedProject) {
    log.fine("aufgerufen: project="+selectedProject);
    this.selectedProject = selectedProject;
  }
  
  public AnchorPane getProjectHeader(Project pro, String... parts) throws Exception {
    AnchorPane pane = new AnchorPane();
    pane.getStyleClass().add("tool-window");
    pane.setPrefHeight(50);
    if (pro==null) {
      throw new Exception("Project muss angegeben werden!");
    } else {
      HBox breadCrumbs = new HBox(label("Projekt"),label(" > "),label(pro.getTitle()+" ("+pro.getName()+")"));
      for (String part: parts) {
        breadCrumbs.getChildren().addAll(label(" > "),label(part));
      }
      FXHelper.add2AnchorPane(pane, breadCrumbs, 5.0, 5.0, null, null);
    }
    return pane;
  }
  
  public AnchorPane getProjectHeader(Project pro) {
    AnchorPane pane = new AnchorPane();
    pane.getStyleClass().add("tool-window");
    pane.setPrefHeight(50);
    if (pro==null) {
      FXHelper.add2AnchorPane(pane, label("neues Projekt"), 5.0, 5.0, null, null);
    } else {
      HBox breadCrumbs = new HBox(label("Projekt"),label(" > "),label(pro.getTitle()+" ("+pro.getName()+")"));
      FXHelper.add2AnchorPane(pane, breadCrumbs, 5.0, 5.0, null, null);
    }
    return pane;
  }
  
  private Label label(String title) {
    Label l3 = new Label(title);
    l3.getStyleClass().add("title-label");
    return l3;
  }
  
}
